﻿using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WCAD
{
    public class SiChaShu
    {
        QuadTreeNode<Circle> qtree;
        List<Circle> cirs;
        [CommandMethod("CreateCircles")]
        public void CreateCircles()
        {
            /*
             * 有人说不知道四叉树怎么用，那我就写个demo吧。
             * 四叉树用于存储平面物体的位置数据，并根据位置快速返回物体，具体原理请百度
             * 这个例子是这样的，做十万个圆，圆心在（1000，1000）这个范围内随机。 
             * 然后我们随便点一个点。返回这个点附近100范围内的圆。
             */
            Document dm = Application.DocumentManager.MdiActiveDocument;
            Random rand = new Random();
            cirs = new List<Circle>();

            //做十万个小圆
            for (int i = 0; i < 100000; i++)
            {
                Point3d cent = new Point3d(rand.NextDouble() * 1000, rand.NextDouble() * 1000, 0);
                Circle cir = new Circle(cent, Vector3d.ZAxis, rand.NextDouble() * 1 + 1);
                cir.ColorIndex = rand.Next(255);
                cirs.Add(cir);
            }
            //new 四叉树，把小圆添加到四叉树里
            qtree = new QuadTreeNode<Circle>(0, 0, 1000, 1000, 100000);
            for (int i = 0; i < cirs.Count; i++)
            {
                //这里只是添加了圆心，所以只能查找到圆心点。
                //你也可以添加圆的四个象限点。那么如果象限点满足条件，也可以找到。
                qtree.AddNode(cirs[i].Center, cirs[i]);
            }

            //把圆添加到数据库
            using (Transaction tr = dm.Database.TransactionManager.StartTransaction())
            {
                BlockTable bt = (BlockTable)tr.GetObject(dm.Database.BlockTableId, OpenMode.ForRead);
                BlockTableRecord btr = (BlockTableRecord)tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite);
                for (int i = 0; i < cirs.Count; i++)
                {
                    cirs[i].SetDatabaseDefaults();
                    btr.AppendEntity(cirs[i]);
                    tr.AddNewlyCreatedDBObject(cirs[i], true);
                }
                tr.Commit();
            }

            ViewTableRecord acView = new ViewTableRecord();
            acView.Height = 1200;
            acView.Width = 1200;
            acView.CenterPoint = new Point2d(500, 500);
            dm.Editor.SetCurrentView(acView);

        }
        [CommandMethod("Scs")]
        public void Scs()
        {
            Document dm = Application.DocumentManager.MdiActiveDocument;
            //任选一点
            PromptPointResult ppr = dm.Editor.GetPoint("选择一点");
            if (ppr.Status == PromptStatus.OK)
            {
                Stopwatch stopwatch = new Stopwatch();
                stopwatch.Start();
                Point3d pt = ppr.Value;
                List<Circle> cirsref = new List<Circle>();
                // 查找这个点周围100范围内的对象，用ref返回
                qtree.GetNodeRecRange(pt, 100, ref cirsref);
                //亮显这些圆
                cirsref.ForEach(c => c.Highlight());
                stopwatch.Stop();
                dm.Editor.WriteMessage("使用四叉树，用时" + stopwatch.ElapsedMilliseconds + "毫秒");
            }

            /*
             * 四叉树里可以添加任何对象，比如线，文字，块参照，甚至序号，啥都行，
             * 只要把对象和点对应上，就是用点来表示这个对象的位置，
             * 如果一个对象不能用一个点来完全表示他的位置。那么重复添加这个对象，并设置多个点
             * 比如一个直线的两个端点，或者一条曲线上等分的若干个点。一个文字的四个角点，等等。
             * 请自由发挥。
             */
        }
        [CommandMethod("Nscs")]
        public void Nscs()
        {
            Document dm = Application.DocumentManager.MdiActiveDocument;
            //任选一点
            PromptPointResult ppr = dm.Editor.GetPoint("选择一点");
            if (ppr.Status == PromptStatus.OK)
            {
                Stopwatch stopwatch = new Stopwatch();
                stopwatch.Start();
                Point3d pt = ppr.Value;
                List<Circle> cirsref = new List<Circle>();
                // 查找这个点周围100范围内的对象
                foreach (var item in cirs)
                {
                    if(item.Center.DistanceTo(pt)<100) cirsref.Add(item);
                }
                //亮显这些圆
                cirsref.ForEach(c => c.Highlight());
                stopwatch.Stop();
                dm.Editor.WriteMessage("不使用四叉树，用时" + stopwatch.ElapsedMilliseconds + "毫秒");
            }

            /*
             * 四叉树里可以添加任何对象，比如线，文字，块参照，甚至序号，啥都行，
             * 只要把对象和点对应上，就是用点来表示这个对象的位置，
             * 如果一个对象不能用一个点来完全表示他的位置。那么重复添加这个对象，并设置多个点
             * 比如一个直线的两个端点，或者一条曲线上等分的若干个点。一个文字的四个角点，等等。
             * 请自由发挥。
             */
        }
    }
}
